<?php

namespace App\Libraries\Payment\WechatPay;

use App\Libraries\Payment\PaymentInterface;
use App\Models\Setting;
use App\Services\Withdraw\UserWithdrawService;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Facades\Log;
use WeChatPay\Builder;
use WeChatPay\BuilderChainable;
use WeChatPay\Crypto\Rsa;
use WeChatPay\Formatter;
use WeChatPay\Util\PemUtil;


class WechatPayPayment implements PaymentInterface
{
    public static function config()
    {
        $config = config('wechat.payment.default');
        if(Setting::get("app_id") && Setting::get("app_secret")){

            $config['app_id'] = Setting::get("app_id");
        }
        return $config;
    }

    protected static function instance(): BuilderChainable
    {
        $config = self::config();

        // 获取项目根目录（适用于各种服务器）
        $basePath = realpath(__DIR__ . '/../../../../'); // 获取当前代码所在目录的上一级

        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        //$merchantPrivateKeyFilePath = 'file://' . $config['key_path'];
        $merchantPrivateKeyFilePath = 'file://' . realpath($basePath . '/' . $config['key_path']);

        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath);

        // 「商户API证书」的「证书序列号」
        $merchantCertificateSerial = $config['api_cert_serial'];

        // 从本地文件中加载「微信支付平台证书」，用来验证微信支付应答的签名
        //$platformCertificateFilePath = 'file://' . $config['platform_cet_path'];
        $platformCertificateFilePath = 'file://' . realpath($basePath . '/' . $config['platform_cet_path']);
        $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC);

        // 从「微信支付平台证书」中获取「证书序列号」
        $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath);

        // 构造一个 APIv3 客户端实例
        return Builder::factory([
            'mchid' => $config['mch_id'],
            'serial' => $merchantCertificateSerial,
            'privateKey' => $merchantPrivateKeyInstance,
            'certs' => [
                $platformCertificateSerial => $platformPublicKeyInstance,
            ],
        ]);
    }

    /*public static function makeRequest(array $params): string
    {
        $config = self::config();
        $instance = self::instance();
        // 分
        $moneyInCent = $params['transAmount'] * 100;
        UserWithdrawService::checkAccountBank($params['transAmount']);

        if (env('PAYMENT_SANDBOX')) {
            return self::fakeRequest($params);
        }

        try {
            $resp = $instance->chain('v3/transfer/batches')->post([
                'verify' => false, // 关闭 SSL 验证,//本地测试使用
                'json' => [
                    'appid' => $config['app_id'],
                    'out_batch_no' => $params['transactionNo'],
                    'batch_name' => $params['remark'],
                    'batch_remark' => $params['remark'],
                    'total_amount' => $moneyInCent,
                    'total_num' => 1,
                    'transfer_detail_list' => [
                        [
                            'out_detail_no' => $params['batchDetailNo'],
                            'transfer_amount' => $moneyInCent,
                            'transfer_remark' => $params['remark'],
                            'openid' => $params['accountNo'],
                        ]
                    ],
                    'notify_url' => $params['notifyUrl'],
                ],
            ]);

        } catch (ClientException $exception) {
            throw new \Exception($exception->getResponse()->getBody()->getContents());
        }
        $content = json_decode($resp->getBody()->getContents(), true);

        Log::channel('transfer')->debug(
            json_encode([
                'request' => $content,
            ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
        );
        $batchId = $content['batch_id'] ?? '';
        if (empty($batchId)) {
            throw new \Exception('转账发起失败');
        }

        return $batchId;
    }*/
    public static function makeRequest(array $params)
    {
        $config = self::config();

        $instance = self::instance();
        // 分
        $moneyInCent = $params['transAmount'] * 100;
        UserWithdrawService::checkAccountBank($params['transAmount']);

        try {
            $resp = $instance->chain('v3/fund-app/mch-transfer/transfer-bills')->post([
                'verify' => false, // 关闭 SSL 验证,//本地测试使用
                'json' => [
                    'appid' => $config['app_id'],
                    'out_bill_no' => $params['transactionNo'],
                    'transfer_scene_id'=>"1005",
                    'openid'=>$params['accountNo'],
                    'transfer_amount' => $moneyInCent,
                    'transfer_remark' =>$params['remark'],
                    'transfer_scene_report_infos'=>[
                        [
                            'info_type'=>"岗位类型",
                            'info_content'=>"新会员有礼"
                        ],
                        [
                            'info_type'=>"报酬说明",
                            'info_content'=>"注册会员抽奖一等奖"
                        ]
                    ],

                    'notify_url' => $params['notifyUrl'],
                ],
                // 'json' => [
                //     'appid' => $config['app_id'],
                //     'out_bill_no' => $params['transactionNo'],
                //     'transfer_scene_id'=>"1000",
                //     'openid'=>$params['accountNo'],
                //     'transfer_amount' => $moneyInCent,
                //     'transfer_remark' =>$params['remark'],
                //     'transfer_scene_report_infos'=>[
                //         [
                //             'info_type'=>"活动名称",
                //             'info_content'=>"新会员有礼"
                //         ],
                //         [
                //             'info_type'=>"奖励说明",
                //             'info_content'=>"注册会员抽奖一等奖"
                //         ]
                //     ],

                //     'notify_url' => $params['notifyUrl'],
                // ],
            ]);

        } catch (ClientException $exception) {
            throw new \Exception($exception->getResponse()->getBody()->getContents());
        }
        $content = json_decode($resp->getBody()->getContents(), true);

        Log::channel('transfer')->debug(
            json_encode([
                'request' => $content,
            ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
        );
        $batchId = $content['transfer_bill_no'] ?? '';
        $package_info = $content['package_info'] ?? '';
        if (empty($batchId)) {
            throw new \Exception('转账发起失败');
        }

        return ['orderId'=>$batchId,'package_info'=>$package_info];
    }
    public static function fakeRequest(array $params): string
    {
        $orderId = strtoupper(uniqid());
        Log::channel('sandbox')->debug([
            'orderId' => $orderId,
            'params' => $params,
        ]);

        return $orderId;
    }


    public static function makePrepay(array $params)
    {
        $config = self::config();
        $instance = self::instance();
        // 发送请求
        $resp = $instance->chain('v3/pay/transactions/app')->post([
            'verify' => false, // 关闭 SSL 验证,//本地测试使用
            'json' => [
                'appid' => $config['app_id'],
                'mchid' => $config['mch_id'],
                'description' => $params['body'],
                'out_trade_no' => $params['out_trade_no'],
                'notify_url' => $params['notify_url'],
                'amount' => [
                    'total' => $params['total_fee'],
                    'currency' => 'CNY',
                ]
            ],
        ]);
        $content = json_decode($resp->getBody()->getContents(), true);
        Log::channel('payment')->info($content);
        if (!$prepayId = ($content['prepay_id'] ?? null)) {
            throw new \Exception('prepay_id 获取失败');
        }

        $payload = [
            'appid' => $config['app_id'],
            'partnerid' => $config['mch_id'],
            'prepayid' => $prepayId,
        ];

        return self::signPrepay($payload);
    }

    /*public static function makeInquiry(array $params)
    {
        $instance = self::instance();

        try {
            // https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-detail/get-transfer-detail-by-out-no.html
            $resp = $instance->chain("v3/transfer/batches/out-batch-no/{$params['out_batch_no']}/details/out-detail-no/{$params['out_batch_detail_no']}")->get();
            $content = json_decode($resp->getBody()->getContents(), true);
        } catch (ClientException $exception) {
            $message = $exception->getResponse()->getBody()->getContents();

            return json_decode($message, true);
        }

        return $content;
    }*/
    public static function makeInquiry(array $params)
    {
        $instance = self::instance();
        try {
            // https://pay.weixin.qq.com/docs/merchant/apis/batch-transfer-to-balance/transfer-detail/get-transfer-detail-by-out-no.html
            $resp = $instance->chain("/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/".$params['out_batch_no'])->get();
            $content = json_decode($resp->getBody()->getContents(), true);
        } catch (ClientException $exception) {
            $message = $exception->getResponse()->getBody()->getContents();

            return json_decode($message, true);
        }

        return $content;
    }

    public static function cancel(){

        $instance = self::instance();

        // 发送请求
        $resp = $instance->chain('/v3/fund-app/mch-transfer/transfer-bills/out-bill-no/20250416555257525748/cancel')->post([
            'verify' => false, // 关闭 SSL 验证,//本地测试使用
        ]);

        $content = json_decode($resp->getBody()->getContents(), true);
        dd($content);
    }

    protected static function signPrepay(array $params)
    {
        $config = self::config();

        // 获取项目根目录（适用于各种服务器）
        $basePath = realpath(__DIR__ . '/../../../../'); // 获取当前代码所在目录的上一级

        // 从本地文件中加载「商户API私钥」，「商户API私钥」会用来生成请求的签名
        //$merchantPrivateKeyFilePath = 'file://' . $config['key_path'];
        $merchantPrivateKeyFilePath = 'file://' . realpath($basePath . '/' . $config['key_path']);;
        $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath);

        // 'appid' => $result['appid'],
        // 'noncestr' => $result['nonce_str'],
        // 'package' => 'Sign=WXPay',
        // 'partnerid' => $result['mch_id'],
        // 'prepayid' => $result['prepay_id'],
        // 'timestamp' => sprintf('%s', time()),
        // 'sign' => $result['sign'],

        $prepayParams = [
            'appid' => $config['app_id'],
            'timestamp' => (string)Formatter::timestamp(),
            'noncestr' => Formatter::nonce(),
            'prepayid' => $params['prepayid'],
        ];
        $prepayParams += [
            'sign' =>
                Rsa::sign(
                    Formatter::joinedByLineFeed(...array_values($prepayParams)),
                    $merchantPrivateKeyInstance
                ),
            // 'signType' => 'RSA'
        ];
        $prepayParams = array_merge([
            'partnerid' => $params['partnerid'],
            'package' => 'Sign=WXPay',
        ], $prepayParams);

        return $prepayParams;
    }
}
